import pickle

import pygame
from pygame.locals import *


class Map():
    """
    编辑地图类
        参数：
        tg main主类引用
    """

    def __init__(self, tg):
        self.tg = tg
        self.wall_type = 5  # 墙默认为5，空白墙
        self.init()

    def init(self):
        self.start_pos = None  # 初始化鼠标按下的起点
        self.end_pos = None  # 初始化鼠标松开的终点
        self.button = None  # 初始化鼠标按键类型

    # event参数是主类传送过来的事件参数
    def update(self, event):
        if event.type == MOUSEBUTTONDOWN:  # 如果鼠标按下
            self.mouse_down(event)
        if event.type == MOUSEBUTTONUP:  # 如果鼠标松开
            self.mouse_up(event)
        if event.type == MOUSEMOTION:  # 如果鼠标移动
            if self.start_pos is not None:
                self.draw_rect(event.pos)
        if event.type == KEYDOWN:
            # 如果键盘按下，按照键盘1、2、3、4分别对应土、草、水、钢墙，修改墙类型
            if event.key == K_1:
                self.wall_type = 0
            elif event.key == K_2:
                self.wall_type = 1
            elif event.key == K_3:
                self.wall_type = 2
            elif event.key == K_4:
                self.wall_type = 3
            elif event.key == K_ESCAPE:
                # 如果按下Esc键，侧保存编辑中的地图，返回到菜单界面
                self.tg.is_edit_map = False
                self.tg.is_show_menu = True
                self.save()

    def cursor(self):
        # 根据墙类型，修改鼠标指针跟随
        pos = pygame.mouse.get_pos()
        self.tg.screen.blit(self.tg.images.wall[self.wall_type], pos)

    def save(self):
        # 遍历所有墙，把坐标和类型保存到数组中
        map_list = []
        for wall in self.tg.maps:
            map_list.append((wall.type, wall.x, wall.y))
        # 把数组转换成元组，并更改内存中的墙数据
        self.tg.map_data[self.tg.edit_checkpoint]['data'] = tuple(map_list)
        # 打开墙数据文件，把修改后的墙数据写入到文件中
        with open('map.pkl', 'wb') as f:
            pickle.dump(self.tg.map_data, f)
        # 清空当前编辑的墙数据
        self.tg.maps.empty()
        # 清空已初始化的墙
        self.tg.walls.empty()
        # 根据修改后的地图，重新初始化墙
        self.tg.init_wall()

    # event事件参数
    def mouse_down(self, event):
        # 当鼠标按下，记录鼠标按下时的坐标，和鼠标按键类型
        if event.button is 1:
            self.start_pos = event.pos
            self.button = 1
        elif event.button is 3:
            self.start_pos = event.pos
            self.button = 3

    # event事件参数
    def mouse_up(self, event):
        # 当鼠标松开，记录鼠标松开的坐标
        if event.button is 1:
            self.end_pos = event.pos
            self.button = 1
        elif event.button is 3:
            self.end_pos = event.pos
            self.button = 3
        self.operation()

    # pos 坐标值
    def draw_rect(self, pos):
        # 当鼠标移动时，不断生成一个矩形框
        self.tg.select_rect = pygame.Rect(self.rect(pos))

    # pos 坐标值
    def rect(self, pos):
        # 通过两个坐标位置计算出一个矩形框
        pos_x = self.start_pos[0], pos[0]
        pos_y = self.start_pos[1], pos[1]
        x = min(pos_x)  # 取两个坐标的x的最小值为左上角x
        y = min(pos_y)  # 取两个坐标的y的最小值为左上角y
        w = abs(self.start_pos[0] - pos[0])  # 计算两个坐标x之间的绝对值距离为w宽
        h = abs(self.start_pos[1] - pos[1])  # 计算两个坐标y之间的绝对值距离为h高
        return x, y, w, h

    def operation(self):
        # 如果起始坐标和结束坐标都不为空
        if self.start_pos is not None and self.end_pos is not None:
            # 清除选择框
            self.tg.select_rect = None
            # 创建一个选择框大小的精灵
            select = Select(*self.rect(self.end_pos))
            # 精灵与所有墙进行碰撞检测
            collide_list = pygame.sprite.spritecollide(select, self.tg.maps, False)
            for map in collide_list:
                # 对与选择框相碰的墙，根据鼠标按键类型和墙类型修改当前墙的类型
                if self.button == 1:
                    # 按键类型为左键1，修改当前墙与默认墙类型一个
                    map.image = map.images[self.wall_type]
                    map.type = self.wall_type
                elif self.button == 3:
                    # 若为鼠标右键3，修改当前墙类型为空白墙
                    map.image = map.images[5]
                    map.type = 5
            self.init()  # 重新初始化起点坐标和结束坐标，鼠标按钮类型，等待下次动作


class Select(pygame.sprite.Sprite):
    """
    一个只有基础属性的精灵类
    """

    def __init__(self, x, y, w, h):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([w, h])
        self.rect = self.image.get_rect()
        self.rect.x, self.rect.y = x, y
